The R markdown is available from the pulldown menu for Code at the upper-right, choose “Download Rmd”, or download the Rmd from GitHub.


This vignette will demonstrate network retrieval from the STRING database, basic analysis, loading and visualization TCGA data in Cytoscape from R using the RCy3 package. Relevant subnetworks will be identified using different strategies, including network connectivity.

At the end of this vignette, you will have will be a visualization of TCGA data on a subnetwork built around highly mutated genes in the relevant cancer type.


Required Software

The whole point of RCy3 is to connect with Cytoscape. You will need to install and launch Cytoscape:

For this vignette, you’ll also need the STRING app to access the STRING database from within Cytoscape:

Getting Disease Networks

Use Cytoscape to query the STRING database for networks of genes associated with breast cancer and ovarian cancer.

If the STRING app is not installed, no error is reported, but your network will be empty

Query STRING database by disease to generate networks

Breast cancer

Here we are using Cytoscape’s command line syntax, which can be used for any core or app automation function, and then making a GET request. Use commandsHelp to interrogate the functions and parameters available in your active Cytoscape session, including the apps you’ve installed!

Interacting with Cytoscape

Now that we’ve got a couple networks into Cytoscape, let’s see what we can do with them from R…

Get list of networks

Get table data from network

Now, let’s look at the tablular data associated with our STRING networks…

One of the great things about the STRING database is all the node and edge attriubtes they provide. Let’s pull some of it into R to play with…

Retrieve disease scores

We can retrieve any set of columns from Cytoscape and store them as an R data frame keyed by SUID. In this case, let’s retrieve the disease score column from the node table. Those will be our two parameters:

Visualizing data on networks

Breast Cancer Datset

These datasets are similar to the data frames you normally encounter in R. For diversity, one using row.names to store corresponding gene names and the other uses the first column. Both are easy to import into Cytoscape.

Let’s return to the Breast Cancer network…

…and use the helper function from RCy3 called loadTableData

Visual styles

Let’s create a new style to visualize our imported data …starting with the basics, we will specify a few defaults and obvious mappings in a custom style all our own.

Visualize expression data

Now let’s update the style with a mapping for mean expression. The first step is to grab the column data from Cytoscape and pull out the min and max to define our data mapping range of values.

Next, we use the RColorBrewer package to help us pick good colors to pair with our data values.

Finally, we use the handy mapVisualProperty function to construct the data object that CyREST needs to specify style mappings and then we’ll send them off to Cytoscape with updateStyleMappings.

Pro-tip: depending on your data, it may be better to balance your color range over negative and positive values bounded by the largest min or max data value, so that color intensity scales similarly in both directions.

Subnetwork based on diffusion from heavily mutated nodes

Now, let’s pull in what we learned about subnetwork selection and apply it here…

The top mutated genes are based on TCGA data and the diffusion algorithm is operating based on the network connectivity from STRING data, leading to a focused subnetwork view of critical Breast Cancer genes with mean patient expression data mapped to fill color. Now that’s data integration!

Pro-tip: You can generate a legend for this in Cytoscape Style tab > Options > Create style… This is no yet available as a command. Coming soon!

Ovarian Cancer Datset

But what about the other network and datasets? Do we have to repeat all of those steps again? Actually, no!

First, let’s switch back over to the Ovarian Cancer network and load our data.

Because we used the same column names in our original data frames, now we can simply apply the same visual style created above!

Reusing the same style for both breast and ovarian cancers, we can compare the relative expression and mutation counts across the two datasets. For example, notice in the case of ovarian cancer: decreased range of mean expression and fewer mega-mutated genes.

Saving, sharing and publishing

Saving a Cytoscape session file

Session files save everything. As with most project software, we recommend saving often!

Note: If you don’t specify a complete path, the files will be saved relative to your current working directory in R.

Saving high resolution image files

You can export extremely high resolution images, including vector graphic formats.

LS0tCnRpdGxlOiAiQ2FuY2VyIG5ldHdvcmtzIGFuZCBkYXRhIgphdXRob3I6ICJieSBBbGV4YW5kZXIgUGljbyIKcGFja2FnZTogUkN5MwpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiAibm9uZSIKIyAgcGRmX2RvY3VtZW50OgojICAgIHRvYzogdHJ1ZSAgIAp2aWduZXR0ZTogPgogICAgJVxWaWduZXR0ZUluZGV4RW50cnl7MDYuIENhbmNlciBuZXR3b3JrcyBhbmQgZGF0YSB+NDAgbWlufQogICAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQogICAgJVxWaWduZXR0ZUVuY29kaW5ne1VURi04fQotLS0KYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGV2YWw9RkFMU0UKKQpgYGAKKlRoZSBSIG1hcmtkb3duIGlzIGF2YWlsYWJsZSBmcm9tIHRoZSBwdWxsZG93biBtZW51IGZvciogQ29kZSAqYXQgdGhlIHVwcGVyLXJpZ2h0LCBjaG9vc2UgIkRvd25sb2FkIFJtZCIsIG9yIFtkb3dubG9hZCB0aGUgUm1kIGZyb20gR2l0SHViXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vY3l0b3NjYXBlL2N5dG9zY2FwZS1hdXRvbWF0aW9uL21hc3Rlci9mb3Itc2NyaXB0ZXJzL1Ivbm90ZWJvb2tzL0NhbmNlci1uZXR3b3Jrcy1hbmQtZGF0YS5SbWQpLioKCjxociAvPgpUaGlzIHZpZ25ldHRlIHdpbGwgZGVtb25zdHJhdGUgbmV0d29yayByZXRyaWV2YWwgZnJvbSB0aGUgU1RSSU5HIGRhdGFiYXNlLCBiYXNpYyBhbmFseXNpcywgbG9hZGluZyBhbmQgdmlzdWFsaXphdGlvbiBUQ0dBIGRhdGEgaW4gQ3l0b3NjYXBlIGZyb20gUiB1c2luZyB0aGUgUkN5MyBwYWNrYWdlLiBSZWxldmFudCBzdWJuZXR3b3JrcyB3aWxsIGJlIGlkZW50aWZpZWQgdXNpbmcgZGlmZmVyZW50IHN0cmF0ZWdpZXMsIGluY2x1ZGluZyBuZXR3b3JrIGNvbm5lY3Rpdml0eS4KCkF0IHRoZSBlbmQgb2YgdGhpcyB2aWduZXR0ZSwgeW91IHdpbGwgaGF2ZSB3aWxsIGJlIGEgdmlzdWFsaXphdGlvbiBvZiBUQ0dBIGRhdGEgb24gYSBzdWJuZXR3b3JrIGJ1aWx0IGFyb3VuZCBoaWdobHkgbXV0YXRlZCBnZW5lcyBpbiB0aGUgcmVsZXZhbnQgY2FuY2VyIHR5cGUuCgo8Y2VudGVyPgohW10oaHR0cHM6Ly9jeXRvc2NhcGUuZ2l0aHViLmlvL2N5dG9zY2FwZS1hdXRvbWF0aW9uL2Zvci1zY3JpcHRlcnMvUi9ub3RlYm9va3MvZGF0YS9pbWcvYnJjNC5wbmcpCjwvY2VudGVyPgoKPGhyIC8+CgojIEluc3RhbGxhdGlvbgpgYGB7cn0KaWYoISJSQ3kzIiAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKXsKICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJSQ3kzIikKfQpsaWJyYXJ5KFJDeTMpCgppZighIlJDb2xvckJyZXdlciIgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKSl7CiAgICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQp9CmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCiMgUmVxdWlyZWQgU29mdHdhcmUKVGhlIHdob2xlIHBvaW50IG9mIFJDeTMgaXMgdG8gY29ubmVjdCB3aXRoIEN5dG9zY2FwZS4gWW91IHdpbGwgbmVlZCB0byBpbnN0YWxsIGFuZCBsYXVuY2ggQ3l0b3NjYXBlOiAKICAgIAoqIERvd25sb2FkIHRoZSBsYXRlc3QgQ3l0b3NjYXBlIGZyb20gaHR0cDovL3d3dy5jeXRvc2NhcGUub3JnL2Rvd25sb2FkLnBocAoqIENvbXBsZXRlIGluc3RhbGxhdGlvbiB3aXphcmQKKiBMYXVuY2ggQ3l0b3NjYXBlIAoKYGBge3J9CmN5dG9zY2FwZVBpbmcoKQpgYGAKCkZvciB0aGlzIHZpZ25ldHRlLCB5b3UnbGwgYWxzbyBuZWVkIHRoZSBbU1RSSU5HIGFwcF0oaHR0cHM6Ly9hcHBzLmN5dG9zY2FwZS5vcmcvYXBwcy9zdHJpbmdhcHApIHRvIGFjY2VzcyB0aGUgU1RSSU5HIGRhdGFiYXNlIGZyb20gd2l0aGluIEN5dG9zY2FwZToKCmBgYHtyfQojYXZhaWxhYmxlIGluIEN5dG9zY2FwZSAzLjcuMCBhbmQgYWJvdmUKaW5zdGFsbEFwcCgnU1RSSU5HYXBwJykgIApgYGAKCiMgR2V0dGluZyBEaXNlYXNlIE5ldHdvcmtzCgpVc2UgQ3l0b3NjYXBlIHRvIHF1ZXJ5IHRoZSBTVFJJTkcgZGF0YWJhc2UgZm9yIG5ldHdvcmtzIG9mIGdlbmVzIGFzc29jaWF0ZWQgd2l0aCBicmVhc3QgY2FuY2VyIGFuZCBvdmFyaWFuIGNhbmNlci4KCioqSWYgdGhlIFNUUklORyBhcHAgaXMgbm90IGluc3RhbGxlZCwgbm8gZXJyb3IgaXMgcmVwb3J0ZWQsIGJ1dCB5b3VyIG5ldHdvcmsgIHdpbGwgYmUgZW1wdHkqKgoKIyMgUXVlcnkgU1RSSU5HIGRhdGFiYXNlIGJ5IGRpc2Vhc2UgdG8gZ2VuZXJhdGUgbmV0d29ya3MKIyMjIEJyZWFzdCBjYW5jZXIKYGBge3J9CnN0cmluZy5jbWQgPSAnc3RyaW5nIGRpc2Vhc2UgcXVlcnkgZGlzZWFzZT0iYnJlYXN0IGNhbmNlciIgY3V0b2ZmPTAuOSBzcGVjaWVzPSJIb21vIHNhcGllbnMiIGxpbWl0PTE1MCcKY29tbWFuZHNSdW4oc3RyaW5nLmNtZCkKYGBgCkhlcmUgd2UgYXJlIHVzaW5nIEN5dG9zY2FwZSdzIGNvbW1hbmQgbGluZSBzeW50YXgsIHdoaWNoIGNhbiBiZSB1c2VkIGZvciBhbnkgY29yZSBvciBhcHAKYXV0b21hdGlvbiBmdW5jdGlvbiwgYW5kIHRoZW4gbWFraW5nIGEgR0VUIHJlcXVlc3QuIFVzZSAqY29tbWFuZHNIZWxwKiB0byBpbnRlcnJvZ2F0ZSAKdGhlIGZ1bmN0aW9ucyBhbmQgcGFyYW1ldGVycyBhdmFpbGFibGUgaW4geW91ciBhY3RpdmUgQ3l0b3NjYXBlIHNlc3Npb24sIGluY2x1ZGluZyB0aGUgCmFwcHMgeW91J3ZlIGluc3RhbGxlZCEKCiFbXSguL2RhdGEvaW1nL2JyYy5wbmcpe2hlaWdodD0xMDAlfSAgCgojIyMgT3ZhcmlhbiBjYW5jZXIKYGBge3J9CnN0cmluZy5jbWQgPSAnc3RyaW5nIGRpc2Vhc2UgcXVlcnkgZGlzZWFzZT0ib3ZhcmlhbiBjYW5jZXIiIGN1dG9mZj0wLjkgc3BlY2llcz0iSG9tbyBzYXBpZW5zIiBsaW1pdD0xNTAnCmNvbW1hbmRzUnVuKHN0cmluZy5jbWQpCmBgYAoKIVtdKC4vZGF0YS9pbWcvb3ZjLnBuZyl7aGVpZ2h0PTEwMCV9CgojIEludGVyYWN0aW5nIHdpdGggQ3l0b3NjYXBlIAoKTm93IHRoYXQgd2UndmUgZ290IGEgY291cGxlIG5ldHdvcmtzIGludG8gQ3l0b3NjYXBlLCBsZXQncyBzZWUgd2hhdCB3ZSBjYW4gZG8gd2l0aCB0aGVtIGZyb20gUi4uLgoKIyMgR2V0IGxpc3Qgb2YgbmV0d29ya3MgCmBgYHtyfQpnZXROZXR3b3JrTGlzdCgpCmBgYAoKIyMgTGF5b3V0IG5ldHdvcmsKYGBge3J9CmxheW91dE5ldHdvcmsobGF5b3V0Lm5hbWU9J2NpcmN1bGFyJykgCmBgYAoKIVtdKC4vZGF0YS9pbWcvb3ZjMi5wbmcpe2hlaWdodD0xMDAlfSAKCiMjIyBMaXN0IG9mIGxheW91dCBhbGdvcml0aG1zIGF2YWlsYWJsZQpgYGB7cn0KZ2V0TGF5b3V0TmFtZXMoKQpgYGAKCiMjIyBMYXlvdXQgd2l0aCBwYXJhbWV0ZXJzIQpgYGB7cn0KZ2V0TGF5b3V0UHJvcGVydHlOYW1lcyhsYXlvdXQubmFtZT0nZm9yY2UtZGlyZWN0ZWQnKQpsYXlvdXROZXR3b3JrKCdmb3JjZS1kaXJlY3RlZCBkZWZhdWx0U3ByaW5nQ29lZmZpY2llbnQ9MC4wMDAwMDA4IGRlZmF1bHRTcHJpbmdMZW5ndGg9NzAnKQpgYGAKCiMjIEdldCB0YWJsZSBkYXRhIGZyb20gbmV0d29yawpOb3csIGxldCdzIGxvb2sgYXQgdGhlIHRhYmx1bGFyIGRhdGEgYXNzb2NpYXRlZCB3aXRoIG91ciBTVFJJTkcgbmV0d29ya3MuLi4KYGBge3J9CmdldFRhYmxlQ29sdW1uTmFtZXMoJ25vZGUnKQpgYGAKCk9uZSBvZiB0aGUgZ3JlYXQgdGhpbmdzIGFib3V0IHRoZSBTVFJJTkcgZGF0YWJhc2UgaXMgYWxsIHRoZSBub2RlIGFuZCBlZGdlIGF0dHJpdWJ0ZXMgdGhleSBwcm92aWRlLiBMZXQncyBwdWxsIHNvbWUgb2YgaXQgaW50byBSIHRvIHBsYXkgd2l0aC4uLgoKIyMjIFJldHJpZXZlIGRpc2Vhc2Ugc2NvcmVzIApXZSBjYW4gcmV0cmlldmUgYW55IHNldCBvZiBjb2x1bW5zIGZyb20gQ3l0b3NjYXBlIGFuZCBzdG9yZSB0aGVtIGFzIGFuIFIgZGF0YSBmcmFtZSBrZXllZCBieSBTVUlELiBJbiB0aGlzIGNhc2UsIGxldCdzIHJldHJpZXZlIHRoZSBkaXNlYXNlIHNjb3JlIGNvbHVtbiBmcm9tIHRoZSBub2RlIHRhYmxlLiBUaG9zZSB3aWxsIGJlIG91ciB0d28gcGFyYW1ldGVyczoKYGBge3J9CmRpc2Vhc2Uuc2NvcmUudGFibGUgPC0gZ2V0VGFibGVDb2x1bW5zKCdub2RlJywnc3RyaW5nZGI6OmRpc2Vhc2Ugc2NvcmUnKQpkaXNlYXNlLnNjb3JlLnRhYmxlCmBgYAoKIyMjIFBsb3QgZGlzdHJpYnV0aW9uIGFuZCBwaWNrIHRocmVzaG9sZApOb3cgeW91IGNhbiB1c2UgUiBsaWtlIHlvdSBub3JtYWxseSB3b3VsZCBleHBsb3JlIHRoZSBkYXRhLgpgYGB7cn0KcGFyKG1hcj1jKDEsMSwxLDEpKQpwbG90KGZhY3Rvcihyb3cubmFtZXMoZGlzZWFzZS5zY29yZS50YWJsZSkpLGRpc2Vhc2Uuc2NvcmUudGFibGVbLDFdLCB5bGFiPWNvbG5hbWVzKGRpc2Vhc2Uuc2NvcmUudGFibGUpWzFdKQpzdW1tYXJ5KGRpc2Vhc2Uuc2NvcmUudGFibGUpCmBgYAoKIyMgR2VuZXJhdGUgc3VibmV0d29ya3MKSW4gb3JkZXIgdG8gcmVmbGVjdCB5b3VyIGV4cGxvcmF0aW9uIGJhY2sgb250byB0aGUgbmV0d29yaywgbGV0J3MgZ2VuZXJhdGUgc3VibmV0d29ya3MuLi4KCi4uLmZyb20gdG9wIHF1YXJ0aWxlIG9mICdkaXNlYXNlIHNjb3JlJwpgYGB7cn0KdG9wLnF1YXJ0IDwtIHF1YW50aWxlKGRpc2Vhc2Uuc2NvcmUudGFibGVbLDFdLCAwLjc1KQp0b3Aubm9kZXMgPC0gcm93Lm5hbWVzKGRpc2Vhc2Uuc2NvcmUudGFibGUpW3doaWNoKGRpc2Vhc2Uuc2NvcmUudGFibGVbLDFdPnRvcC5xdWFydCldCmNyZWF0ZVN1Ym5ldHdvcmsodG9wLm5vZGVzLHN1Ym5ldHdvcmsubmFtZSA9J3RvcCBkaXNlYXNlIHF1YXJ0aWxlJykKI3JldHVybnMgYSBDeXRvc2NhcGUgbmV0d29yayBTVUlECmBgYAoKLi4ub2YgY29ubmVjdGVkIG5vZGVzIG9ubHkKYGBge3J9CmNyZWF0ZVN1Ym5ldHdvcmsoZWRnZXM9J2FsbCcsc3VibmV0d29yay5uYW1lPSd0b3AgZGlzZWFzZSBxdWFydGlsZSBjb25uZWN0ZWQnKSAgI2hhbmR5IHdheSB0byBleGNsdWRlIHVuY29ubmVjdGVkIG5vZGVzIQpgYGAKCi4uLmZyb20gZmlyc3QgbmVpZ2hib3JzIG9mIHRvcCAzIGdlbmVzLCB1c2luZyB0aGUgbmV0d29yayBjb25uZWN0aXZpdHkgdG9nZXRoZXIgd2l0aCB0aGUgZGF0YSB0byBkaXJlY3QgZGlzY292ZXJ5LgpgYGB7cn0Kc2V0Q3VycmVudE5ldHdvcmsobmV0d29yaz0iU3RyaW5nIE5ldHdvcmsgLSBvdmFyaWFuIGNhbmNlciIpCnRvcC5ub2RlcyA8LSByb3cubmFtZXMoZGlzZWFzZS5zY29yZS50YWJsZSlbdGFpbChvcmRlcihkaXNlYXNlLnNjb3JlLnRhYmxlWywxXSksMyldCnNlbGVjdE5vZGVzKG5vZGVzPXRvcC5ub2RlcykKc2VsZWN0Rmlyc3ROZWlnaGJvcnMoKQpjcmVhdGVTdWJuZXR3b3JrKCdzZWxlY3RlZCcsIHN1Ym5ldHdvcmsubmFtZT0ndG9wIGRpc2Vhc2UgbmVpZ2hib3JzJykgIyBzZWxlY3RlZCBub2RlcywgYWxsIGNvbm5lY3RpbmcgZWRnZXMgKGRlZmF1bHQpCmBgYAoKLi4uZnJvbSBkaWZmdXNpb24gYWxnb3JpdGhtIHN0YXJ0aW5nIHdpdGggdG9wIDMgZ2VuZXMsIHVzaW5nIHRoZSBuZXR3b3JrIGNvbm5lY3Rpdml0eSBpbiBhIG1vcmUgc3VidGxlIHdheSB0aGFuIGp1c3QgZmlyc3QtZGVncmVlIG5laWdoYm9ycy4KYGBge3J9CnNldEN1cnJlbnROZXR3b3JrKG5ldHdvcms9IlN0cmluZyBOZXR3b3JrIC0gb3ZhcmlhbiBjYW5jZXIiKQpzZWxlY3ROb2Rlcyhub2Rlcz10b3Aubm9kZXMpCmRpZmZ1c2lvbkJhc2ljKCkgIyBkaWZmdXNpb24hCmNyZWF0ZVN1Ym5ldHdvcmsoJ3NlbGVjdGVkJyxzdWJuZXR3b3JrLm5hbWUgPSAndG9wIGRpc2Vhc2UgZGlmZnVzaW9uJykKbGF5b3V0TmV0d29yaygnZm9yY2UtZGlyZWN0ZWQnKQpgYGAKCiFbXSguL2RhdGEvaW1nL292YzQucG5nKXtoZWlnaHQ9MTAwJX0gCgoqUHJvLXRpcCo6IGRvbid0IGZvcmdldCB0byAqKnNldEN1cnJlbnROZXR3b3JrKCkqKiB0byB0aGUgY29ycmVjdCBwYXJlbnQgbmV0d29yayBiZWZvcmUgZ2V0dGluZyB0YWJsZSBjb2x1bW4gZGF0YSBhbmQgbWFraW5nIHNlbGVjdGlvbnMuCgojIFZpc3VhbGl6aW5nIGRhdGEgb24gbmV0d29ya3MKCiMjIExvYWQgZGF0YXNldHMKRG93bmxvYWRlZCBUQ0dBIGRhdGEsIHByZXByb2Nlc3NlZCBhcyBSIG9iamVjdHMuIEFsc28gYXZhaWxhYmxlIHZpYSBlYWNoIFRDR0EgcHVibGljYXRpb24sIGUuZy46CiAKKiBCcmVhc3Q6IGh0dHBzOi8vdGNnYS1kYXRhLm5jaS5uaWguZ292L2RvY3MvcHVibGljYXRpb25zL2JyY2FfMjAxMi8KKiBPdmFyaWFuOiBodHRwczovL3RjZ2EtZGF0YS5uY2kubmloLmdvdi9kb2NzL3B1YmxpY2F0aW9ucy9vdl8yMDExLwogIApgYGB7cn0KbG9hZChzeXN0ZW0uZmlsZSgiZXh0ZGF0YSIsInR1dG9yaWFsLW92Yy1leHByLW1lYW4tZGF0YXNldC5yb2JqIiwgcGFja2FnZT0iUkN5MyIpKQpsb2FkKHN5c3RlbS5maWxlKCJleHRkYXRhIiwidHV0b3JpYWwtb3ZjLW11dC1kYXRhc2V0LnJvYmoiLCBwYWNrYWdlPSJSQ3kzIikpCmxvYWQoc3lzdGVtLmZpbGUoImV4dGRhdGEiLCJ0dXRvcmlhbC1icmMtZXhwci1tZWFuLWRhdGFzZXQucm9iaiIsIHBhY2thZ2U9IlJDeTMiKSkKbG9hZChzeXN0ZW0uZmlsZSgiZXh0ZGF0YSIsInR1dG9yaWFsLWJyYy1tdXQtZGF0YXNldC5yb2JqIiwgcGFja2FnZT0iUkN5MyIpKQpgYGAKCgojIyBCcmVhc3QgQ2FuY2VyIERhdHNldApUaGVzZSBkYXRhc2V0cyBhcmUgc2ltaWxhciB0byB0aGUgZGF0YSBmcmFtZXMgeW91IG5vcm1hbGx5IGVuY291bnRlciBpbiBSLiBGb3IgZGl2ZXJzaXR5LCBvbmUgdXNpbmcgcm93Lm5hbWVzIHRvIHN0b3JlIGNvcnJlc3BvbmRpbmcgZ2VuZSBuYW1lcyBhbmQgdGhlIG90aGVyIHVzZXMgdGhlIGZpcnN0IGNvbHVtbi4gQm90aCBhcmUgZWFzeSB0byBpbXBvcnQgaW50byBDeXRvc2NhcGUuCmBgYHtyfQpzdHIoYnJjLmV4cHIpICAjIGdlbmUgbmFtZXMgaW4gcm93Lm5hbWVzIG9mIGRhdGEuZnJhbWUKc3RyKGJyYy5tdXQpICAjIGdlbmUgbmFtZXMgaW4gY29sdW1uIG5hbWVkICdIdWdvX1N5bWJvbCcKYGBgCgpMZXQncyByZXR1cm4gdG8gdGhlIEJyZWFzdCBDYW5jZXIgbmV0d29yay4uLgpgYGB7cn0Kc2V0Q3VycmVudE5ldHdvcmsobmV0d29yaz0iU3RyaW5nIE5ldHdvcmsgLSBicmVhc3QgY2FuY2VyIikKbGF5b3V0TmV0d29yaygnZm9yY2UtZGlyZWN0ZWQnKSAjdXNlcyBzYW1lIHNldHRpbmdzIGFzIHByZXZpb3VzbHkgc2V0CmBgYAoKLi4uYW5kIHVzZSB0aGUgaGVscGVyIGZ1bmN0aW9uIGZyb20gUkN5MyBjYWxsZWQgKmxvYWRUYWJsZURhdGEqCmBgYHtyfQo/bG9hZFRhYmxlRGF0YQpsb2FkVGFibGVEYXRhKGJyYy5leHByLHRhYmxlLmtleS5jb2x1bW4gPSAiZGlzcGxheSBuYW1lIikgICNkZWZhdWx0IGRhdGEuZnJhbWUga2V5IGlzIHJvdy5uYW1lcwpsb2FkVGFibGVEYXRhKGJyYy5tdXQsJ0h1Z29fU3ltYm9sJyx0YWJsZS5rZXkuY29sdW1uID0gImRpc3BsYXkgbmFtZSIpICAjc3BlY2lmeSBjb2x1bW4gbmFtZSBpZiBub3QgZGVmYXVsdApgYGAKCiMjIyBWaXN1YWwgc3R5bGVzCkxldCdzIGNyZWF0ZSBhIG5ldyBzdHlsZSB0byB2aXN1YWxpemUgb3VyIGltcG9ydGVkIGRhdGEKLi4uc3RhcnRpbmcgd2l0aCB0aGUgYmFzaWNzLCB3ZSB3aWxsIHNwZWNpZnkgYSBmZXcgZGVmYXVsdHMgYW5kIG9idmlvdXMgbWFwcGluZ3MgaW4gYSBjdXN0b20gc3R5bGUgYWxsIG91ciBvd24uCmBgYHtyfQpzdHlsZS5uYW1lID0gImRhdGFTdHlsZSIKY3JlYXRlVmlzdWFsU3R5bGUoc3R5bGUubmFtZSkKc2V0VmlzdWFsU3R5bGUoc3R5bGUubmFtZSkKCnNldE5vZGVTaGFwZURlZmF1bHQoImVsbGlwc2UiLCBzdHlsZS5uYW1lKSAjcmVtZW1iZXIgdG8gc3BlY2lmeSB5b3VyIHN0eWxlLm5hbWUhCnNldE5vZGVTaXplRGVmYXVsdCg2MCwgc3R5bGUubmFtZSkKc2V0Tm9kZUNvbG9yRGVmYXVsdCgiI0FBQUFBQSIsIHN0eWxlLm5hbWUpCnNldEVkZ2VMaW5lV2lkdGhEZWZhdWx0KDIsIHN0eWxlLm5hbWUpCnNldE5vZGVMYWJlbE1hcHBpbmcoJ2Rpc3BsYXkgbmFtZScsIHN0eWxlLm5hbWUpCmBgYAoKIyMjIyBWaXN1YWxpemUgZXhwcmVzc2lvbiBkYXRhCk5vdyBsZXQncyB1cGRhdGUgdGhlIHN0eWxlIHdpdGggYSBtYXBwaW5nIGZvciBtZWFuIGV4cHJlc3Npb24uIFRoZSBmaXJzdCBzdGVwIGlzIHRvIGdyYWIgdGhlIGNvbHVtbiBkYXRhIGZyb20gQ3l0b3NjYXBlIGFuZCBwdWxsIG91dCB0aGUgbWluIGFuZCBtYXggdG8gZGVmaW5lIG91ciBkYXRhIG1hcHBpbmcgcmFuZ2Ugb2YgdmFsdWVzLgpgYGB7cn0KYnJjLmV4cHIubmV0d29yayA9IGdldFRhYmxlQ29sdW1ucygnbm9kZScsJ2V4cHIubWVhbicpICAKbWluLmJyYy5leHByID0gbWluKGJyYy5leHByLm5ldHdvcmtbLDFdLG5hLnJtPVRSVUUpCm1heC5icmMuZXhwciA9IG1heChicmMuZXhwci5uZXR3b3JrWywxXSxuYS5ybT1UUlVFKQpkYXRhLnZhbHVlcyA9IGMobWluLmJyYy5leHByLDAsbWF4LmJyYy5leHByKQpgYGAKCk5leHQsIHdlIHVzZSB0aGUgUkNvbG9yQnJld2VyIHBhY2thZ2UgdG8gaGVscCB1cyBwaWNrIGdvb2QgY29sb3JzIHRvIHBhaXIgd2l0aCBvdXIgZGF0YSB2YWx1ZXMuIApgYGB7cn0KZGlzcGxheS5icmV3ZXIuYWxsKGxlbmd0aChkYXRhLnZhbHVlcyksIGNvbG9yYmxpbmRGcmllbmRseT1UUlVFLCB0eXBlPSJkaXYiKSAjIGRpdixxdWFsLHNlcSxhbGwKbm9kZS5jb2xvcnMgPC0gYyhyZXYoYnJld2VyLnBhbChsZW5ndGgoZGF0YS52YWx1ZXMpLCAiUmRCdSIpKSkKYGBgCgpGaW5hbGx5LCB3ZSB1c2UgdGhlIGhhbmR5ICptYXBWaXN1YWxQcm9wZXJ0eSogZnVuY3Rpb24gdG8gY29uc3RydWN0IHRoZSBkYXRhIG9iamVjdCB0aGF0IEN5UkVTVCBuZWVkcyB0byBzcGVjaWZ5IHN0eWxlIG1hcHBpbmdzIGFuZCB0aGVuIHdlJ2xsIHNlbmQgdGhlbSBvZmYgdG8gQ3l0b3NjYXBlIHdpdGggKnVwZGF0ZVN0eWxlTWFwcGluZ3MqLgpgYGB7cn0Kc2V0Tm9kZUNvbG9yTWFwcGluZygnZXhwci5tZWFuJywgZGF0YS52YWx1ZXMsIG5vZGUuY29sb3JzLCBzdHlsZS5uYW1lPXN0eWxlLm5hbWUpCmBgYAoKIVtdKC4vZGF0YS9pbWcvYnJjMi5wbmcpe2hlaWdodD0xMDAlfSAKCioqUHJvLXRpcDogZGVwZW5kaW5nIG9uIHlvdXIgZGF0YSwgaXQgbWF5IGJlIGJldHRlciB0byBiYWxhbmNlIHlvdXIgY29sb3IgcmFuZ2Ugb3ZlciBuZWdhdGl2ZSBhbmQgcG9zaXRpdmUgdmFsdWVzIGJvdW5kZWQgYnkgdGhlIGxhcmdlc3QgbWluIG9yIG1heCBkYXRhIHZhbHVlLCBzbyB0aGF0IGNvbG9yIGludGVuc2l0eSBzY2FsZXMgc2ltaWxhcmx5IGluIGJvdGggZGlyZWN0aW9ucy4qKgoKIyMjIFZpc3VhbGl6ZSBtdXRhdGlvbiBkYXRhCk9LLCBub3cgbGV0J3MgdXBkYXRlIHdpdGggYSBtYXBwaW5nIGZvciBtdXRhdGlvbi4gSGVyZSBhcmUgYWxsIHRoZSBzYW1lIHN0ZXBzLCBidXQgdGhpcyB0aW1lIG1hcHBpbmcgbXV0YXRpb24gY291bnRzIHRvICpib3RoKiBub2RlIGJvcmRlciB3aWR0aCBhbmQgY29sb3IuIApgYGB7cn0KYnJjLm11dC5uZXR3b3JrID0gZ2V0VGFibGVDb2x1bW5zKCdub2RlJywnbXV0X2NvdW50JykKbWluLmJyYy5tdXQgPSBtaW4oYnJjLm11dC5uZXR3b3JrWywxXSxuYS5ybT1UUlVFKQptYXguYnJjLm11dCA9IG1heChicmMubXV0Lm5ldHdvcmtbLDFdLG5hLnJtPVRSVUUpCmRhdGEudmFsdWVzID0gYyhtaW4uYnJjLm11dCwyMCxtYXguYnJjLm11dCkKZGlzcGxheS5icmV3ZXIuYWxsKGxlbmd0aChkYXRhLnZhbHVlcyksIGNvbG9yYmxpbmRGcmllbmRseT1UUlVFLCB0eXBlPSJzZXEiKSAKYm9yZGVyLmNvbG9ycyA8LSBjKGJyZXdlci5wYWwoMywgIlJlZHMiKSkKc2V0Tm9kZUJvcmRlckNvbG9yTWFwcGluZygnbXV0X2NvdW50JyxkYXRhLnZhbHVlcyxib3JkZXIuY29sb3JzLHN0eWxlLm5hbWU9c3R5bGUubmFtZSkKYm9yZGVyLndpZHRoIDwtIGMoMiw0LDgpCnNldE5vZGVCb3JkZXJXaWR0aE1hcHBpbmcoJ211dF9jb3VudCcsZGF0YS52YWx1ZXMsYm9yZGVyLndpZHRoLHN0eWxlLm5hbWU9c3R5bGUubmFtZSkKYGBgClRoaXMgaXMgYSB1c2VmdWwgcGFpciBvZiB2aXN1YWwgcHJvcGVydGllcyB0byBtYXAgdG8gYSBzaW5nbGUgZGF0YSBjb2x1bW4uIFNlZSB3aHk/CgohW10oLi9kYXRhL2ltZy9icmMzLnBuZyl7aGVpZ2h0PTEwMCV9IAoKIyMjIFN1Ym5ldHdvcmsgYmFzZWQgb24gZGlmZnVzaW9uIGZyb20gaGVhdmlseSBtdXRhdGVkIG5vZGVzCk5vdywgbGV0J3MgcHVsbCBpbiB3aGF0IHdlIGxlYXJuZWQgYWJvdXQgc3VibmV0d29yayBzZWxlY3Rpb24gYW5kIGFwcGx5IGl0IGhlcmUuLi4KYGBge3J9CnRvcC5tdXQgPC0gKGJyYy5tdXQkSHVnb19TeW1ib2wpW3RhaWwob3JkZXIoYnJjLm11dCRtdXRfY291bnQpLDIpXQp0b3AubXV0CnNlbGVjdE5vZGVzKG5vZGVzPXRvcC5tdXQsJ2Rpc3BsYXkgbmFtZScpCmRpZmZ1c2lvbkJhc2ljKCkgCmNyZWF0ZVN1Ym5ldHdvcmsoJ3NlbGVjdGVkJyxzdWJuZXR3b3JrLm5hbWUgPSAndG9wIG11dGF0ZWQgZGlmZnVzaW9uJykKbGF5b3V0TmV0d29yaygnZm9yY2UtZGlyZWN0ZWQnKQpgYGAKClRoZSB0b3AgbXV0YXRlZCBnZW5lcyBhcmUgYmFzZWQgb24gVENHQSBkYXRhIGFuZCB0aGUgZGlmZnVzaW9uIGFsZ29yaXRobSBpcyBvcGVyYXRpbmcgYmFzZWQgb24gdGhlIG5ldHdvcmsgY29ubmVjdGl2aXR5IGZyb20gU1RSSU5HIGRhdGEsIGxlYWRpbmcgdG8gYSBmb2N1c2VkIHN1Ym5ldHdvcmsgdmlldyBvZiBjcml0aWNhbCBCcmVhc3QgQ2FuY2VyIGdlbmVzIHdpdGggbWVhbiBwYXRpZW50IGV4cHJlc3Npb24gZGF0YSBtYXBwZWQgdG8gZmlsbCBjb2xvci4gTm93ICp0aGF0J3MqIGRhdGEgaW50ZWdyYXRpb24hCgohW10oLi9kYXRhL2ltZy9icmM0LnBuZyl7aGVpZ2h0PTEwMCV9IAoKKipQcm8tdGlwOiBZb3UgY2FuIGdlbmVyYXRlIGEgbGVnZW5kIGZvciB0aGlzIGluIEN5dG9zY2FwZSBTdHlsZSB0YWIgPiBPcHRpb25zID4gQ3JlYXRlIHN0eWxlLi4uICBUaGlzIGlzIG5vIHlldCBhdmFpbGFibGUgYXMgYSBjb21tYW5kLiBDb21pbmcgc29vbiEqKgoKIyMgT3ZhcmlhbiBDYW5jZXIgRGF0c2V0CkJ1dCB3aGF0IGFib3V0IHRoZSBvdGhlciBuZXR3b3JrIGFuZCBkYXRhc2V0cz8gRG8gd2UgaGF2ZSB0byByZXBlYXQgKmFsbCogb2YgdGhvc2Ugc3RlcHMgYWdhaW4/ICBBY3R1YWxseSwgbm8hCgpGaXJzdCwgbGV0J3Mgc3dpdGNoIGJhY2sgb3ZlciB0byB0aGUgT3ZhcmlhbiBDYW5jZXIgbmV0d29yayBhbmQgbG9hZCBvdXIgZGF0YS4KYGBge3J9CnNldEN1cnJlbnROZXR3b3JrKG5ldHdvcms9IlN0cmluZyBOZXR3b3JrIC0gb3ZhcmlhbiBjYW5jZXIiKQpjbGVhclNlbGVjdGlvbigpCnN0cihvdmMuZXhwcikgICMgZ2VuZSBuYW1lcyBpbiByb3cubmFtZXMgb2YgZGF0YS5mcmFtZQpzdHIob3ZjLm11dCkgICMgZ2VuZSBuYW1lcyBpbiBjb2x1bW4gbmFtZWQgJ0h1Z29fU3ltYm9sJwoKbG9hZFRhYmxlRGF0YShvdmMuZXhwciwgdGFibGUua2V5LmNvbHVtbiA9ICdkaXNwbGF5IG5hbWUnKQpsb2FkVGFibGVEYXRhKG92Yy5tdXQsJ0h1Z29fU3ltYm9sJywgdGFibGUua2V5LmNvbHVtbiA9ICdkaXNwbGF5IG5hbWUnKQpgYGAKCioqQmVjYXVzZSB3ZSB1c2VkIHRoZSBzYW1lIGNvbHVtbiBuYW1lcyBpbiBvdXIgb3JpZ2luYWwgZGF0YSBmcmFtZXMsIG5vdyB3ZSBjYW4gc2ltcGx5IGFwcGx5IHRoZSAqc2FtZSogdmlzdWFsIHN0eWxlIGNyZWF0ZWQgYWJvdmUhKioKYGBge3J9CnNldFZpc3VhbFN0eWxlKHN0eWxlLm5hbWU9c3R5bGUubmFtZSkKYGBgCgohW10oLi9kYXRhL2ltZy9vdmMzLnBuZyl7aGVpZ2h0PTEwMCV9ICAKClJldXNpbmcgdGhlIHNhbWUgc3R5bGUgZm9yIGJvdGggYnJlYXN0IGFuZCBvdmFyaWFuIGNhbmNlcnMsIHdlIGNhbiBjb21wYXJlIHRoZSByZWxhdGl2ZSBleHByZXNzaW9uIGFuZCBtdXRhdGlvbiBjb3VudHMgYWNyb3NzIHRoZSB0d28gZGF0YXNldHMuIApGb3IgZXhhbXBsZSwgbm90aWNlIGluIHRoZSBjYXNlIG9mIG92YXJpYW4gY2FuY2VyOiAqKmRlY3JlYXNlZCoqIHJhbmdlIG9mIG1lYW4gZXhwcmVzc2lvbiBhbmQgKipmZXdlcioqIG1lZ2EtbXV0YXRlZCBnZW5lcy4KCiMgU2F2aW5nLCBzaGFyaW5nIGFuZCBwdWJsaXNoaW5nCgojIyBTYXZpbmcgYSBDeXRvc2NhcGUgc2Vzc2lvbiBmaWxlClNlc3Npb24gZmlsZXMgc2F2ZSAqZXZlcnl0aGluZyouIEFzIHdpdGggbW9zdCBwcm9qZWN0IHNvZnR3YXJlLCB3ZSByZWNvbW1lbmQgc2F2aW5nIG9mdGVuIQpgYGB7cn0Kc2F2ZVNlc3Npb24oJ3R1dG9yaWFsX3Nlc3Npb24nKSAjLmN5cwpgYGAKKipOb3RlOioqIElmIHlvdSBkb24ndCBzcGVjaWZ5IGEgY29tcGxldGUgcGF0aCwgdGhlIGZpbGVzIHdpbGwgYmUgc2F2ZWQgcmVsYXRpdmUgdG8geW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGluIFIuIAoKIyMgU2F2aW5nIGhpZ2ggcmVzb2x1dGlvbiBpbWFnZSBmaWxlcwpZb3UgY2FuIGV4cG9ydCBleHRyZW1lbHkgaGlnaCByZXNvbHV0aW9uIGltYWdlcywgaW5jbHVkaW5nIHZlY3RvciBncmFwaGljIGZvcm1hdHMuCmBgYHtyfQpleHBvcnRJbWFnZShmaWxlbmFtZT0ndHV0b3JpYWxfaW1hZ2UyJywgdHlwZSA9ICdQREYnKSAjLnBkZgo/ZXhwb3J0SW1hZ2UKYGBgCgo=